package imp

import (
	sqlc "bgs/db/sqlc"
	"bgs/db/sqlc/ctype"
	activityGrpc "bgs/grpc/gen/service/activity"
	commonActivityGrpc "bgs/grpc/gen/shared/common_activity"
	"bgs/grpc/gen/shared/message"
	activityService "bgs/service/activity"
	"bgs/service/model"
	"bgs/util"
	"encoding/json"
	"fmt"

	"context"
	"database/sql"
)

/****************************************************************************************/
/*                               activity entity of helper                              */
/****************************************************************************************/

func transformTimeRangeEntityToPb(trs []ctype.TimeRange) (timeRangeEntities []*message.TimeRange) {
	for _, tr := range trs {
		timeRangeEntities = append(timeRangeEntities, &message.TimeRange{
			BeginAt: tr.BeginAt,
			EndAt:   tr.EndAt,
		})
	}
	return
}

func transformActivityOfBEntityToPb(warehouseIds []int64,
	activityProductWithProductInfos []sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow,
	activitySkuWithProductOrProductSpecInfos []*model.ActivitySkuWithProductOrProductSpecInfo,
	activityConsignmentPtr *sqlc.ActivityConsignment,
	activityConsignmentBonusSettings []sqlc.ActivityConsignmentBonusSetting) func(sqlc.Activity) *activityGrpc.ActivityOfBEntity {
	return func(o sqlc.Activity) *activityGrpc.ActivityOfBEntity {
		v := &activityGrpc.ActivityOfBEntity{
			Id:                            o.ID,
			BrandId:                       o.BrandID,
			Name:                          o.Name,
			Type:                          o.Type,
			Intro:                         string(o.Intro),
			ProcessStatus:                 o.ProcessStatus,
			Published:                     sqlc.GoNTimeToPBTimestamp(o.Published),
			Begined:                       sqlc.GoTimeToPBTimestamp(o.Begined),
			Ended:                         sqlc.GoTimeToPBTimestamp(o.Ended),
			TimeRanges:                    transformTimeRangeEntityToPb(o.TimeRanges),
			Background:                    o.Background.String,
			Poster:                        o.Poster.String,
			SaleMode:                      o.SaleMode,
			VerifyQualification:           o.VerifyQualification,
			QualifyTypes:                  o.QualifyTypes,
			DeliveryModes:                 o.DeliveryModes,
			IsUseWarehouseShippingFeeRule: o.IsUseWarehouseShippingFeeRule,
			UnifiedShippingFee:            o.UnifiedShippingFee.Int32,
			MaxiumPurchaseFrequency:       o.MaxiumPurchaseFrequency.Int32,
			MinimumPurchaseAmount:         o.MinimumPurchaseAmount,
			Tel:                           o.Tel,
			Owner:                         o.Owner,
			InventoryFreezeNo:             o.InventoryFreezeNo.String,
			WarehouseIds:                  warehouseIds,
			ActivityProductWithSkus:       mapActivityProductWithProductInfoToPb(activityProductWithProductInfos, activitySkuWithProductOrProductSpecInfos, transActivityProductWithProductInfoToPb),
		}

		if activityService.CheckCanEndorse(o.Type) {
			v.Consignment = transActivityConfignmentToPb(*activityConsignmentPtr, activityConsignmentBonusSettings)
		}

		if model.CheckNeedTypeInfo(o.Type) {
			typeInfo := &model.ActivityTypeInfo{}
			json.Unmarshal(o.TypeInfo.RawMessage, typeInfo)
			switch sqlc.EmActivityType(o.Type) {
			case sqlc.EmActivityTypeCheckIn1:
				v.TypeInfo = &activityGrpc.ActivityOfBEntity_CheckIn_1{
					CheckIn_1: &commonActivityGrpc.CheckIn1Entity{
						AwardOnceCoins:     uint32(typeInfo.CheckIn1Ptr.AwardOnceCoins),
						AwardReachMaxCoins: uint32(typeInfo.CheckIn1Ptr.AwardReachMaxCoins),
						Continuous:         uint32(typeInfo.CheckIn1Ptr.MaxContinuous),
					},
				}
			case sqlc.EmActivityTypeLottery1:
				v.TypeInfo = &activityGrpc.ActivityOfBEntity_Lottery_1{
					Lottery_1: &commonActivityGrpc.Lottery1Entity{
						UIType:     typeInfo.Lottery1Ptr.UIType,
						WinRate:    uint32(typeInfo.Lottery1Ptr.WinRate),
						PrizeRates: typeInfo.Lottery1Ptr.PrizeRates,
					},
				}
			default:
			}
		}

		return v
	}
}

func transActivitySkuToPb(i interface{}) *activityGrpc.ActivitySkuEntity {
	o := i.(*model.ActivitySkuWithProductOrProductSpecInfo)
	return &activityGrpc.ActivitySkuEntity{
		Id:             o.ID,
		ProductId:      o.ProductID,
		ProductSpecId:  o.ProductSpecID,
		Price:          o.Price,
		Maximum:        o.Maximum,
		FreezeQuantity: o.FreezeQuantity,
		SoldedQuantity: o.SoldedQuantity,
		StorageKey:     o.StorageKey,
		// product_spec info
		SkuName: o.SkuName,
	}
}

func mapActivitySkuEntityToPb(list []interface{}, f func(interface{}) *activityGrpc.ActivitySkuEntity) []*activityGrpc.ActivitySkuEntity {
	r := make([]*activityGrpc.ActivitySkuEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transActivityProductWithProductInfoToPb(
	o sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow,
	activitySkus []*model.ActivitySkuWithProductOrProductSpecInfo,
) *activityGrpc.ActivityProductWithSkuEntity {

	activitySKUsOfTheActivityProduct := util.Filter(util.ToGenericSlice(activitySkus), func(v interface{}) bool {
		sku := v.(*model.ActivitySkuWithProductOrProductSpecInfo)
		return sku.ProductID == o.ProductID
	})

	return &activityGrpc.ActivityProductWithSkuEntity{
		Id:        o.ID,
		ProductId: o.ProductID,
		PriceMin:  o.PriceMin,
		PriceMax:  o.PriceMax,
		Quantity:  o.Quantity,
		IsShow:    o.IsShow,
		Skus:      mapActivitySkuEntityToPb(activitySKUsOfTheActivityProduct, transActivitySkuToPb),

		// product info
		ProductName: o.ProductName,
		ProductPics: o.ProductPics,
	}
}

func mapActivityProductWithProductInfoToPb(list []sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow, skus []*model.ActivitySkuWithProductOrProductSpecInfo, f func(sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow, []*model.ActivitySkuWithProductOrProductSpecInfo) *activityGrpc.ActivityProductWithSkuEntity) []*activityGrpc.ActivityProductWithSkuEntity {
	r := make([]*activityGrpc.ActivityProductWithSkuEntity, len(list))
	for i, item := range list {
		r[i] = f(item, skus)
	}
	return r
}

func transProductAttributeDefsToPb(productAttributeDefPtr *model.ProductAttributeDef) *message.ProductAttributeDef {
	return &message.ProductAttributeDef{
		Key:    productAttributeDefPtr.Key,
		Values: productAttributeDefPtr.Values,
	}
}

func mapProductAttributeDefsToPb(list []*model.ProductAttributeDef, f func(productAttributeDefPtr *model.ProductAttributeDef) *message.ProductAttributeDef) []*message.ProductAttributeDef {
	r := make([]*message.ProductAttributeDef, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transActivityProductWithAttributeDefAndSkuToPb(
	o sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow,
	mapOfProductAttributeDefs model.AttributeDefMapOfProduct,
	activitySkus []*model.ActivitySkuWithProductOrProductSpecInfo,
) *activityGrpc.ActivityProductWithAttributeDefAndSkuEntity {

	activitySKUsOfTheActivityProduct := util.Filter(util.ToGenericSlice(activitySkus), func(v interface{}) bool {
		sku := v.(*model.ActivitySkuWithProductOrProductSpecInfo)
		return sku.ProductID == o.ProductID
	})

	return &activityGrpc.ActivityProductWithAttributeDefAndSkuEntity{
		Id:        o.ID,
		ProductId: o.ProductID,
		PriceMin:  o.PriceMin,
		PriceMax:  o.PriceMax,
		Quantity:  o.Quantity,
		IsShow:    o.IsShow,
		// todo:aaaa
		ProductAttributeDefs: mapProductAttributeDefsToPb(mapOfProductAttributeDefs[o.ProductID], transProductAttributeDefsToPb),
		Skus:                 mapActivitySkuEntityToPb(activitySKUsOfTheActivityProduct, transActivitySkuToPb),

		// product info
		ProductName:      o.ProductName,
		ProductPics:      o.ProductPics,
		ProductIntro:     o.ProductIntro,
		ProductIntroPics: o.ProductIntroPics,
	}
}

func mapActivityProductWithAttributeDefAndSkuToPb(list []sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow, mapOfProductAttributeDefs model.AttributeDefMapOfProduct, skus []*model.ActivitySkuWithProductOrProductSpecInfo, f func(sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow, model.AttributeDefMapOfProduct, []*model.ActivitySkuWithProductOrProductSpecInfo) *activityGrpc.ActivityProductWithAttributeDefAndSkuEntity) []*activityGrpc.ActivityProductWithAttributeDefAndSkuEntity {
	r := make([]*activityGrpc.ActivityProductWithAttributeDefAndSkuEntity, len(list))
	for i, item := range list {
		r[i] = f(item, mapOfProductAttributeDefs, skus)
	}
	return r
}

func transConsignmentBonusSettingToPb(i interface{}) *activityGrpc.ActivityConsignmentBonusSettingEntity {
	o := i.(sqlc.ActivityConsignmentBonusSetting)
	return &activityGrpc.ActivityConsignmentBonusSettingEntity{
		ProductId: o.ProductID,
		BonusRate: o.BonusRate,
	}
}

func mapConsignmentBonusSettingToPb(list []interface{}, f func(interface{}) *activityGrpc.ActivityConsignmentBonusSettingEntity) []*activityGrpc.ActivityConsignmentBonusSettingEntity {
	r := make([]*activityGrpc.ActivityConsignmentBonusSettingEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transActivityConfignmentToPb(o sqlc.ActivityConsignment, activityConsignmentBonusSettings []sqlc.ActivityConsignmentBonusSetting) *activityGrpc.ActivityConsignmentEntity {
	return &activityGrpc.ActivityConsignmentEntity{
		AllowHiddenProduct:       o.AllowHiddenProduct,
		AllowAllSpokesman:        o.AllowAllSpokesman,
		SpecificSpokesmanIds:     o.SpecificSpokesmanIds,
		ConsignmentBonusSettings: mapConsignmentBonusSettingToPb(util.ToGenericSlice(activityConsignmentBonusSettings), transConsignmentBonusSettingToPb),
		// SpecificSpokesmans:       trans.MapMiniItemToPb(o.SpecificSpokesmanIds, trans.MiniItemToPb),
	}
}

func marshalTypeInfo(activityType sqlc.EmActivityType, v interface{}) (typeInfo ctype.NullRawMessage, err error) {
	var typeInfoPtr *model.ActivityTypeInfo
	switch activityType {
	case sqlc.EmActivityTypeCheckIn1:
		var checkIn1Ptr *commonActivityGrpc.CheckIn1Entity
		valOfCreate, ok := v.(*activityGrpc.CreateActivityOfBRequest_CheckIn_1)
		if !ok {
			checkIn1Ptr = v.(*activityGrpc.UpdateActivityOfBRequest_CheckIn_1).CheckIn_1
		} else {
			checkIn1Ptr = valOfCreate.CheckIn_1
		}
		typeInfoPtr = &model.ActivityTypeInfo{
			CheckIn1Ptr: &model.CheckIn1Info{
				AwardOnceCoins:     model.BCoin(checkIn1Ptr.AwardOnceCoins),
				AwardReachMaxCoins: model.BCoin(checkIn1Ptr.AwardReachMaxCoins),
				MaxContinuous:      checkIn1Ptr.Continuous,
			},
		}
	case sqlc.EmActivityTypeLottery1:
		var Lottery1Ptr *commonActivityGrpc.Lottery1Entity
		valOfCreate, ok := v.(*activityGrpc.CreateActivityOfBRequest_Lottery_1)
		if !ok {
			Lottery1Ptr = v.(*activityGrpc.UpdateActivityOfBRequest_Lottery_1).Lottery_1
		} else {
			Lottery1Ptr = valOfCreate.Lottery_1
		}
		// 这里有个从PrizeRates得出Cardinality
		// maxPrizeRate := strconv.Itoa(int(util.MaxUInt32(valOfCreate.Lottery_1.PrizeRates)))
		// cardinality := math.Pow10(len(maxPrizeRate))
		var cardinality uint32 = 1000
		typeInfoPtr = &model.ActivityTypeInfo{
			Lottery1Ptr: &model.Lottery1Info{
				UIType:      Lottery1Ptr.UIType,
				WinRate:     Lottery1Ptr.WinRate,
				PrizeRates:  Lottery1Ptr.PrizeRates,
				Cardinality: cardinality,
			},
		}
	}
	if typeInfoPtr == nil {
		err = fmt.Errorf("activityType have no mapping type info")
		return
	}
	typeInfoBytes, marshalErr := json.Marshal(typeInfoPtr)
	if marshalErr != nil {
		err = marshalErr
		return
	}
	typeInfo = sqlc.NRawMessageFromRawMessage(json.RawMessage(typeInfoBytes))
	return
}

/****************************************************************************************/
/*                               activity entity of cmd                                 */
/****************************************************************************************/

// CreateActivityOfB B新增活动
func (s *ActivityAPIService) CreateActivityOfB(ctx context.Context, req *activityGrpc.CreateActivityOfBRequest) (res *activityGrpc.CreateActivityOfBResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->CreateActivityOfB:%v", req)
	res = &activityGrpc.CreateActivityOfBResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var activity sqlc.Activity
	var activityWarehouses []sqlc.ActivityWarehouse
	// var activityProducts []sqlc.ActivityProduct
	var activityProductWithProductInfos []sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow
	// var activitySkus []sqlc.ActivitySku
	var activitySkuWithProductOrProductSpecInfos []*model.ActivitySkuWithProductOrProductSpecInfo
	var activityConsignmentPtr *sqlc.ActivityConsignment
	var activityConsignmentBonusSettings []sqlc.ActivityConsignmentBonusSetting
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		brandID := req.BrandId
		if activityService.CheckIsAsFeature(req.Type) {
			exist, err2 := q.CheckExistActivityAsBrandUniqueByBrandIDAndType(ctx, sqlc.CheckExistActivityAsBrandUniqueByBrandIDAndTypeParams{
				BrandID: brandID,
				Type:    string(sqlc.EmActivityTypeCheckIn1),
			})
			if err2 != nil {
				err = err2
				return
			}
			if exist {
				err = fmt.Errorf("品牌下已存在签到活动,不能创建")
				return
			}
		}

		nulInt64 := sqlc.NInt64FromInt64(0)

		p := sqlc.CreateActivityParams{
			BrandID:                       brandID,
			SpokesmanID:                   nulInt64,
			PubUserID:                     req.PubUserId,
			Name:                          req.Name,
			Type:                          req.Type,
			Intro:                         json.RawMessage(req.Intro),
			Begined:                       sqlc.PBTimestampToGoTime(req.Begined),
			Ended:                         sqlc.PBTimestampToGoTime(req.Ended),
			Background:                    sqlc.NSFromString(req.Background),
			SaleMode:                      req.SaleMode,
			DeliveryModes:                 req.DeliveryModes,
			IsUseWarehouseShippingFeeRule: req.IsUseWarehouseShippingFeeRule,
			UnifiedShippingFee:            sqlc.NInt32FromInt32(req.UnifiedShippingFee),
			MaxiumPurchaseFrequency:       sqlc.NInt32FromInt32(req.MaxiumPurchaseFrequency),
			MinimumPurchaseAmount:         req.MinimumPurchaseAmount,
			Tel:                           req.Tel,
			RootID:                        nulInt64,
			ParentID:                      nulInt64,
			Owner:                         string(sqlc.EmActivityOwnerBrand),
		}

		if model.CheckNeedTypeInfo(req.Type) {
			typeInfo, err2 := marshalTypeInfo(sqlc.EmActivityType(req.Type), req.TypeInfo)
			if err2 != nil {
				err = err2
				return
			}
			p.TypeInfo = typeInfo
		}

		if len(req.TimeRanges) > 0 {
			var timeRanges []ctype.TimeRange
			for _, tr := range req.TimeRanges {
				timeRanges = append(timeRanges, ctype.TimeRange{
					BeginAt: tr.BeginAt,
					EndAt:   tr.EndAt,
				})
			}
			p.TimeRanges = timeRanges
		}

		activity, err = q.CreateActivity(ctx, p)
		if err != nil {
			return err
		}
		slog.Infof("1 创建活动B ok")

		// 活动仓库
		var warehouse sqlc.ActivityWarehouse
		for _, warehouseID := range req.WarehouseIds {
			warehouse, err = q.UpsertActivityWarehouse(ctx, sqlc.UpsertActivityWarehouseParams{
				BrandID:          activity.BrandID,
				ActivityID:       activity.ID,
				RootActivityID:   activity.RootID,
				ParentActivityID: activity.ParentID,
				WarehouseID:      warehouseID,
			})
			if err != nil {
				return err
			}
			activityWarehouses = append(activityWarehouses, warehouse)
		}
		slog.Infof("2 设置活动B仓库 ok")

		// 活动商品、商品规格
		var activityProduct sqlc.ActivityProduct
		// var activitySku sqlc.ActivitySku
		for idx1, item1 := range req.ActivityProductWithSkus {
			maxSku, minSku := util.MaxWithMin(util.ToGenericSlice(item1.Skus), func(i1, i2 interface{}) util.Ord {
				ps1, ps2 := i1.(*activityGrpc.ActivitySkuEntity), i2.(*activityGrpc.ActivitySkuEntity)
				return (util.IfThenElse(ps1.Price-ps2.Price < 0, util.Lt, util.Gt)).(util.Ord)
			})
			priceMax, priceMin := maxSku.(*activityGrpc.ActivitySkuEntity).Price, minSku.(*activityGrpc.ActivitySkuEntity).Price
			slog.Infof("max,min %v, %v", priceMax, priceMin)
			quantity := util.Int32IfThenElse(item1.Quantity == 0, 1, item1.Quantity)

			activityProduct, err = q.UpsertActivityProduct(ctx, sqlc.UpsertActivityProductParams{
				BrandID:          activity.BrandID,
				ActivityID:       activity.ID,
				RootActivityID:   activity.RootID,
				ParentActivityID: activity.ParentID,
				ProductID:        item1.ProductId,
				IsShow:           item1.IsShow,
				PriceMin:         priceMin,
				PriceMax:         priceMax,
				Quantity:         quantity,
				SortNo:           int32(idx1 + 1),
			})
			if err != nil {
				return err
			}
			// activityProducts = append(activityProducts, activityProduct)

			for idx2, item2 := range item1.Skus {
				_, err = q.UpsertActivitySku(ctx, sqlc.UpsertActivitySkuParams{
					BrandID:           activity.BrandID,
					ActivityID:        activity.ID,
					RootActivityID:    activity.RootID,
					ParentActivityID:  activity.ParentID,
					ActivityProductID: activityProduct.ID,
					ProductID:         item2.ProductId,
					ProductSpecID:     sqlc.NInt64FromInt64(item2.ProductSpecId),
					Price:             item2.Price,
					Maximum:           util.Int32IfThenElse(item2.Maximum == 0, -1, item2.Maximum),
					ProductSpecKey:    fmt.Sprintf("%d-%d", item2.ProductId, item2.ProductSpecId),
					SortNo:            int32(idx2 + 1),
				})
				if err != nil {
					return err
				}

				// activitySkus = append(activitySkus, activitySku)
			}

		}
		slog.Infof("3 设置活动B商品、商品规格 ok")

		_, err = q.UpdateActivitySkuStoreKeyByActivityID(ctx, activity.ID)
		if err != nil {
			return err
		}
		slog.Infof("3.5 更新storageKey ok")

		if activityService.CheckCanEndorse(activity.Type) {
			// 活动代卖设置
			activityConsignment, err2 := q.UpsertActivityConsignment(ctx, sqlc.UpsertActivityConsignmentParams{
				ActivityID:           activity.ID,
				AllowHiddenProduct:   req.Consignment.AllowHiddenProduct,
				AllowAllSpokesman:    req.Consignment.AllowAllSpokesman,
				SpecificSpokesmanIds: req.Consignment.SpecificSpokesmanIds,
				// SpecificSpokesmans: trans.MapMiniItemFromPb(req.Consignment.SpecificSpokesmans, trans.MiniItemFromPb),
			})
			if err2 != nil {
				return err2
			}
			activityConsignmentPtr = &activityConsignment
			slog.Info("4 设置活动B帮卖 ok")

			//3 活动代卖奖励设置
			var bonusSetting sqlc.ActivityConsignmentBonusSetting
			for _, item := range req.Consignment.ConsignmentBonusSettings {
				bonusSetting, err = q.UpsertActivityConsignmentBonusSetting(ctx, sqlc.UpsertActivityConsignmentBonusSettingParams{
					ActivityID: activity.ID,
					ProductID:  item.ProductId,
					BonusRate:  item.BonusRate,
				})
				if err != nil {
					return err
				}
				activityConsignmentBonusSettings = append(activityConsignmentBonusSettings, bonusSetting)
			}
			slog.Info("5 设置活动B帮卖奖励 ok")
		}

		activityProductWithProductInfos, activitySkuWithProductOrProductSpecInfos, err = s.activityService.FetchNormalProductAndSkus(ctx, q, activity.ID)
		if err != nil {
			return err
		}
		slog.Info("6 读取活动B产品及sku信息 ok ok")

		if activityService.CheckIsAsFeature(activity.Type) {
			warehouseID := req.WarehouseIds[0]
			_, err = s.activityService.PublishActivity(ctx, q, activityService.PublishActivityParam{
				ActivityPtr: &activity,
				UserID:      activity.PubUserID,
				WarehouseID: warehouseID,
				Skus:        activitySkuWithProductOrProductSpecInfos,
			})
			if err != nil {
				return err
			}

			slog.Info("7 功能特性类活动直接发布 ok")
		}

		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.ActivityOfB = transformActivityOfBEntityToPb(req.WarehouseIds, activityProductWithProductInfos, activitySkuWithProductOrProductSpecInfos, activityConsignmentPtr, activityConsignmentBonusSettings)(activity)
	return
}

// UpdateActivityOfB B更新活动
func (s *ActivityAPIService) UpdateActivityOfB(ctx context.Context, req *activityGrpc.UpdateActivityOfBRequest) (res *activityGrpc.UpdateActivityOfBResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->UpdateActivityOfB:%v", req)
	res = &activityGrpc.UpdateActivityOfBResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var activity sqlc.Activity
	var activityWarehouses []sqlc.ActivityWarehouse
	// var activityProducts []sqlc.ActivityProduct
	var activityProductWithProductInfos []sqlc.ListNormalActivityProductWithProductInfosByActivityIDRow
	// var activitySkus []sqlc.ActivitySku
	var activitySkuWithProductOrProductSpecInfos []*model.ActivitySkuWithProductOrProductSpecInfo
	var activityConsignmentPtr *sqlc.ActivityConsignment
	var activityConsignmentBonusSettings []sqlc.ActivityConsignmentBonusSetting
	var toDisableActivityConsignmentBonusSettingIDs []int64
	activityID := req.Id

	activity, err = s.dao.Q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	// 更新前置分析
	normalActivityWarehousesExist, err := s.dao.Q.ListNormalBrandActivityWarehousesByActivityID(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	newWarehouseIDs := req.WarehouseIds
	toDisableActivityWarehouseIDs := util.MapToInt64(util.Filter(util.ToGenericSlice(normalActivityWarehousesExist), func(v interface{}) bool {
		val := v.(sqlc.ActivityWarehouse)
		return !util.Int64Contains(newWarehouseIDs, val.WarehouseID)
	}), func(v interface{}) int64 {
		val := v.(sqlc.ActivityWarehouse)
		return val.ID
	})
	slog.Infof("toDisableActivityWarehouseIDs->%v", toDisableActivityWarehouseIDs)

	var newActivitySkuStorageKeys []string
	newProductIDsOfActivity := util.MapToInt64(util.ToGenericSlice(req.ActivityProductWithSkus), func(v interface{}) int64 {
		val := v.(*activityGrpc.ActivityProductWithSkuEntity)
		currentSkuStorageKeys := util.MapToString(util.ToGenericSlice(val.Skus), func(v interface{}) string {
			val := v.(*activityGrpc.ActivitySkuEntity)
			return fmt.Sprintf("%d-%d", val.ProductId, val.ProductSpecId)
		})
		newActivitySkuStorageKeys = append(newActivitySkuStorageKeys, currentSkuStorageKeys...)
		return val.ProductId
	})
	normalActivityProductsExist, err := s.dao.Q.ListNormalActivityProductsByActivityID(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	// 找出需要disabled的activityProducts
	var toDisableActivityProductIDs []int64
	toDisableProductIDsOfActivityProduct := util.MapToInt64(util.Filter(util.ToGenericSlice(normalActivityProductsExist), func(v interface{}) bool {
		val := v.(sqlc.ActivityProduct)
		return !util.Int64Contains(newProductIDsOfActivity, val.ProductID)
	}), func(v interface{}) int64 {
		val := v.(sqlc.ActivityProduct)
		toDisableActivityProductIDs = append(toDisableActivityProductIDs, val.ID)
		return val.ProductID
	})
	slog.Infof("toDisableActivityProductIDs->%v", toDisableActivityProductIDs)
	slog.Infof("toDisableProductIDsOfActivityProduct->%v", toDisableProductIDsOfActivityProduct)

	// 找出需要disabled的activitySkus
	// a (产品还在,规格没了)
	normalActivitySkusExist, err := s.dao.Q.ListNormalActivitySkusByActivityID(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	toDisableActivitySkuIDs1 := util.MapToInt64(util.Filter(util.ToGenericSlice(normalActivitySkusExist), func(v interface{}) bool {
		val := v.(sqlc.ActivitySku)
		return !util.StringContains(newActivitySkuStorageKeys, fmt.Sprintf("%d-%d", val.ProductID, val.ProductSpecID.Int64))
	}), func(v interface{}) int64 {
		val := v.(sqlc.ProductAttributeValue)
		return val.ID
	})
	slog.Infof("toDisableActivitySkuIDs1->%v", toDisableActivitySkuIDs1)

	// b (产品没了,规格也就没了)
	normalActivitySkusOfToDisableActivityProduct, err := s.dao.Q.ListNormalActivitySkusByActivityIDAndProductIDs(ctx,
		sqlc.ListNormalActivitySkusByActivityIDAndProductIDsParams{
			ActivityID: activityID,
			Column2:    toDisableProductIDsOfActivityProduct,
		})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	toDisableActivitySkuIDs2 := util.MapToInt64(util.ToGenericSlice(normalActivitySkusOfToDisableActivityProduct), func(v interface{}) int64 {
		val := v.(sqlc.ActivitySku)
		return val.ID
	})
	slog.Infof("toDisableActivitySkuIDs2->%v", toDisableActivitySkuIDs2)

	toDisableActivitySkuIDs := append(toDisableActivitySkuIDs1, toDisableActivitySkuIDs2...)
	slog.Infof("toDisableActivitySkuIDs->%v", toDisableActivitySkuIDs)

	if activityService.CheckCanEndorse(activity.Type) {
		// 找出需要disabled的activityConsignmentBonusSettings
		newProductIdsOfConsignmentBonusSetting := util.MapToInt64(util.ToGenericSlice(req.Consignment.ConsignmentBonusSettings), func(v interface{}) int64 {
			val := v.(*activityGrpc.ActivityConsignmentBonusSettingEntity)
			return val.ProductId
		})

		// a (产品还在,帮卖奖励设置没了)
		normalActivityConsignmentBonusSettingsExist, err2 := s.dao.Q.ListNormalActivityConsignmentBonusSettingsByActivityID(ctx, activityID)
		if err != nil {
			res.OpRet = &message.OperationResult{
				Success: false,
				Code:    400,
				Msg:     err2.Error(),
			}
			return
		}
		toDisableActivityConsignmentBonusSettingIDs1 := util.MapToInt64(util.Filter(util.ToGenericSlice(normalActivityConsignmentBonusSettingsExist), func(v interface{}) bool {
			val := v.(sqlc.ActivityConsignmentBonusSetting)
			return !util.Int64Contains(newProductIdsOfConsignmentBonusSetting, val.ProductID)
		}), func(v interface{}) int64 {
			val := v.(sqlc.ProductAttributeValue)
			return val.ID
		})
		slog.Infof("toDisableActivityConsignmentBonusSettingIDs1->%v", toDisableActivityConsignmentBonusSettingIDs1)

		// b (产品没了,帮卖奖励设置也就没了)
		normalActivityConsignmentBonusSettingsOfToDisableActivityProduct, err3 := s.dao.Q.ListNormalActivityConsignmentBonusSettingsByActivityIDAndProductIDs(ctx,
			sqlc.ListNormalActivityConsignmentBonusSettingsByActivityIDAndProductIDsParams{
				ActivityID: activityID,
				Column2:    toDisableProductIDsOfActivityProduct,
			})
		if err != nil {
			res.OpRet = &message.OperationResult{
				Success: false,
				Code:    400,
				Msg:     err3.Error(),
			}
			return
		}
		toDisableActivityConsignmentBonusSettingIDs2 := util.MapToInt64(util.ToGenericSlice(normalActivityConsignmentBonusSettingsOfToDisableActivityProduct), func(v interface{}) int64 {
			val := v.(sqlc.ActivityConsignmentBonusSetting)
			return val.ID
		})
		slog.Infof("toDisableActivityConsignmentBonusSettingIDs2->%v", toDisableActivityConsignmentBonusSettingIDs2)

		toDisableActivityConsignmentBonusSettingIDs = append(toDisableActivityConsignmentBonusSettingIDs1, toDisableActivityConsignmentBonusSettingIDs2...)
		slog.Infof("toDisableActivityConsignmentBonusSettingIDs->%v", toDisableActivityConsignmentBonusSettingIDs)
	}
	slog.Info("更新前置分析完毕")

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		begined := req.Begined
		ended := req.Ended
		maxiumPurchaseFrequency := req.MaxiumPurchaseFrequency
		minimumPurchaseAmount := req.MinimumPurchaseAmount

		p := sqlc.UpdateActivityOfBParams{
			ID:                            activityID,
			Name:                          req.Name,
			Intro:                         json.RawMessage(req.Intro),
			Begined:                       sqlc.PBTimestampToGoTime(begined),
			Ended:                         sqlc.PBTimestampToGoTime(ended),
			Background:                    sqlc.NSFromString(req.Background),
			SaleMode:                      req.SaleMode,
			DeliveryModes:                 req.DeliveryModes,
			IsUseWarehouseShippingFeeRule: req.IsUseWarehouseShippingFeeRule,
			UnifiedShippingFee:            sqlc.NInt32FromInt32(req.UnifiedShippingFee),
			MaxiumPurchaseFrequency:       sqlc.NInt32FromInt32(maxiumPurchaseFrequency),
			MinimumPurchaseAmount:         minimumPurchaseAmount,
			Tel:                           req.Tel,
		}

		if model.CheckNeedTypeInfo(activity.Type) {
			typeInfo, err2 := marshalTypeInfo(sqlc.EmActivityType(activity.Type), req.TypeInfo)
			if err2 != nil {
				err = err2
				return
			}
			p.TypeInfo = typeInfo
		}

		if len(req.TimeRanges) > 0 {
			var timeRanges []ctype.TimeRange
			for _, tr := range req.TimeRanges {
				timeRanges = append(timeRanges, ctype.TimeRange{
					BeginAt: tr.BeginAt,
					EndAt:   tr.EndAt,
				})
			}
			p.TimeRanges = timeRanges
		}

		activity, err = q.UpdateActivityOfB(ctx, p)
		if err != nil {
			return err
		}
		slog.Info("1更新活动B ok")

		existEndorsedActivity, err := q.CheckExistActivitiesOfSpokesmanOwnActivityByParentActivityID(ctx, sqlc.NInt64FromInt64(activity.ID))
		if err != nil {
			return
		}
		if existEndorsedActivity {
			err = q.SyncActivityInfoFromParentActivityByParentActivityID(ctx, sqlc.SyncActivityInfoFromParentActivityByParentActivityIDParams{
				ParentID:                sqlc.NInt64FromInt64(activity.ID),
				Begined:                 sqlc.PBTimestampToGoTime(begined),
				Ended:                   sqlc.PBTimestampToGoTime(ended),
				MaxiumPurchaseFrequency: sqlc.NInt32FromInt32(maxiumPurchaseFrequency),
				MinimumPurchaseAmount:   minimumPurchaseAmount,
			})
			if err != nil {
				return
			}
		}

		if len(toDisableActivityWarehouseIDs) > 0 {
			disableActivityWarehouseRet, err := q.DisableActivityWarehouseByIDs(ctx, toDisableActivityWarehouseIDs)
			if err != nil {
				return err
			}
			slog.Infof("2 disable活动B仓库 ok %v", disableActivityWarehouseRet)
		} else {
			slog.Info("2 没有要disable的活动B仓库 ok")
		}

		var warehouse sqlc.ActivityWarehouse
		for _, warehouseID := range req.WarehouseIds {
			warehouse, err = q.UpsertActivityWarehouse(ctx, sqlc.UpsertActivityWarehouseParams{
				ActivityID:       activity.ID,
				RootActivityID:   activity.RootID,
				ParentActivityID: activity.ParentID,
				WarehouseID:      warehouseID,
			})
			if err != nil {
				return err
			}
			activityWarehouses = append(activityWarehouses, warehouse)
		}
		slog.Infof("3 设置活动B仓库 ok")

		if len(toDisableActivityProductIDs) > 0 {
			disableActivityProductRet, err := q.DisableActivityProductByIDs(ctx, toDisableActivityProductIDs)
			if err != nil {
				return err
			}
			slog.Infof("4 disable活动B商品 ok %v", disableActivityProductRet)
		} else {
			slog.Info("4 没有要disable的活动B商品 ok")
		}

		if len(toDisableActivitySkuIDs) > 0 {
			disableActivitySkuRet, err := q.DisableActivitySkuByIDs(ctx, toDisableActivitySkuIDs)
			if err != nil {
				return err
			}
			slog.Infof("5 disable活动B sku ok %v", disableActivitySkuRet)
		} else {
			slog.Info("5 没有要disable的活动B sku ok")
		}
		// 活动商品、商品规格
		var activityProduct sqlc.ActivityProduct
		// var activitySku sqlc.ActivitySku
		for idx1, item1 := range req.ActivityProductWithSkus {
			maxSku, minSku := util.MaxWithMin(util.ToGenericSlice(item1.Skus), func(i1, i2 interface{}) util.Ord {
				ps1, ps2 := i1.(*activityGrpc.ActivitySkuEntity), i2.(*activityGrpc.ActivitySkuEntity)
				return (util.IfThenElse(ps1.Price-ps2.Price < 0, util.Lt, util.Gt)).(util.Ord)
			})
			priceMax, priceMin := maxSku.(*activityGrpc.ActivitySkuEntity).Price, minSku.(*activityGrpc.ActivitySkuEntity).Price
			slog.Infof("max,min %v, %v", priceMax, priceMin)
			quantity := util.Int32IfThenElse(item1.Quantity == 0, 1, item1.Quantity)

			activityProduct, err = q.UpsertActivityProduct(ctx, sqlc.UpsertActivityProductParams{
				BrandID:          activity.BrandID,
				ActivityID:       activity.ID,
				RootActivityID:   activity.RootID,
				ParentActivityID: activity.ParentID,
				ProductID:        item1.ProductId,
				IsShow:           item1.IsShow,
				PriceMin:         priceMin,
				PriceMax:         priceMax,
				Quantity:         quantity,
				SortNo:           int32(idx1 + 1),
			})
			if err != nil {
				return err
			}
			// activityProducts = append(activityProducts, activityProduct)

			for idx2, item2 := range item1.Skus {
				slog.Infof("item2.ProductId:%d, item2.ProductSpecId:%d", item2.ProductId, item2.ProductSpecId)
				_, err = q.UpsertActivitySku(ctx, sqlc.UpsertActivitySkuParams{
					BrandID:           activity.BrandID,
					ActivityID:        activity.ID,
					RootActivityID:    activity.RootID,
					ParentActivityID:  activity.ParentID,
					ActivityProductID: activityProduct.ID,
					ProductID:         item2.ProductId,
					ProductSpecID:     sqlc.NInt64FromInt64(item2.ProductSpecId),
					Price:             item2.Price,
					Maximum:           util.Int32IfThenElse(item2.Maximum == 0, -1, item2.Maximum),
					ProductSpecKey:    fmt.Sprintf("%d-%d", item2.ProductId, item2.ProductSpecId),
					SortNo:            int32(idx2 + 1),
				})

				if err != nil {
					return err
				}

				// activitySkus = append(activitySkus, activitySku)
			}
		}
		slog.Infof("6 设置活动B商品、商品规格 ok")

		_, err = q.UpdateActivitySkuStoreKeyByActivityID(ctx, activity.ID)
		if err != nil {
			return err
		}
		slog.Infof("6.5 更新storageKey ok")

		if activityService.CheckCanEndorse(activity.Type) {
			// 活动代卖设置
			activityConsignment, err := q.UpsertActivityConsignment(ctx, sqlc.UpsertActivityConsignmentParams{
				ActivityID:           activity.ID,
				AllowHiddenProduct:   req.Consignment.AllowHiddenProduct,
				AllowAllSpokesman:    req.Consignment.AllowAllSpokesman,
				SpecificSpokesmanIds: req.Consignment.SpecificSpokesmanIds,
				// SpecificSpokesmans: trans.MapMiniItemFromPb(req.Consignment.SpecificSpokesmans, trans.MiniItemFromPb),
			})
			if err != nil {
				return err
			}
			activityConsignmentPtr = &activityConsignment
			slog.Info("7 设置活动B帮卖 ok")

			if len(toDisableActivityConsignmentBonusSettingIDs) > 0 {
				disableActivityConsignmentBonusSettingRet, err := q.DisableActivityConsignmentBonusSettingByIDs(ctx, toDisableActivityConsignmentBonusSettingIDs)
				if err != nil {
					return err
				}
				slog.Infof("8 disable活动B代卖奖励设置 ok %v", disableActivityConsignmentBonusSettingRet)
			} else {
				slog.Info("8 没有要disable的活动B代卖奖励设置 ok")
			}

			//3 活动代卖奖励设置
			var bonusSetting sqlc.ActivityConsignmentBonusSetting
			for _, item := range req.Consignment.ConsignmentBonusSettings {
				bonusSetting, err = q.UpsertActivityConsignmentBonusSetting(ctx, sqlc.UpsertActivityConsignmentBonusSettingParams{
					ActivityID: activity.ID,
					ProductID:  item.ProductId,
					BonusRate:  item.BonusRate,
				})
				if err != nil {
					return err
				}
				activityConsignmentBonusSettings = append(activityConsignmentBonusSettings, bonusSetting)
			}
			slog.Info("9 设置活动B帮卖奖励 ok")
		}

		activityProductWithProductInfos, activitySkuWithProductOrProductSpecInfos, err = s.activityService.FetchNormalProductAndSkus(ctx, q, activity.ID)
		if err != nil {
			return err
		}
		slog.Info("10 读取活动B产品及sku信息 ok ok")

		// 更新活动
		if activity.InventoryFreezeNo.Valid {
			activityWarehouse := activityWarehouses[0]
			warehouseID := activityWarehouse.WarehouseID
			err = s.activityService.UpdateInventoryFreezeOrderForB(ctx, &activity, activitySkuWithProductOrProductSpecInfos, warehouseID)
			if err != nil {
				return err
			}
		}

		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	s.activityService.ClearCacheOwn(activity.ID)
	res.ActivityOfB = transformActivityOfBEntityToPb(req.WarehouseIds, activityProductWithProductInfos, activitySkuWithProductOrProductSpecInfos, activityConsignmentPtr, activityConsignmentBonusSettings)(activity)
	return
}

// PublishActivityOfB 发布品牌活动B
func (s *ActivityAPIService) PublishActivityOfB(ctx context.Context, req *activityGrpc.PublishActivityOfBRequest) (res *activityGrpc.PublishActivityOfBResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->PublishActivityOfB:%v", req)
	res = &activityGrpc.PublishActivityOfBResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	activityID := req.Id
	activity, err := s.dao.Q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if activity.Owner != string(sqlc.EmActivityOwnerBrand) {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     fmt.Sprintf("活动owner[%s]不符合", activity.Owner),
		}
		return
	}
	if activity.ProcessStatus != string(sqlc.EmActivityProcessStatusDraft) {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     fmt.Sprintf("活动状态[%s]不允许发布", activity.ProcessStatus),
		}
		return
	}

	var toProcessStatus string

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		cActivity := s.cacher.FetchActivity(activity.ID)
		if cActivity == nil {
			err = fmt.Errorf("not found activity:%d", activity.ID)
			return
		}

		if len(cActivity.WarehouseIDs) != 1 {
			err = fmt.Errorf("too many activity warehouseIDs:%d,%v", activity.ID, cActivity.WarehouseIDs)
			return
		}

		warehouseID := cActivity.WarehouseIDs[0]

		skus, err := s.activityService.FetchNormalSkus(ctx, q, activity.ID)
		if err != nil {
			return
		}

		toProcessStatus, err = s.activityService.PublishActivity(ctx, q, activityService.PublishActivityParam{
			ActivityPtr: &activity,
			UserID:      req.UserId,
			WarehouseID: warehouseID,
			Skus:        skus,
		})
		if err != nil {
			return err
		}
		slog.Infof("a 活动状态改为运行中 ok")
		err = s.activityService.UpdateActivityTypeInfoSinceActivityPublished(ctx, q, &activity)
		if err != nil {
			return err
		}
		slog.Infof("b 活动发布成功后更新类型信息 ok")

		asFeatureTypes := activityService.ActivitiesAsFeature
		err = s.brandService.UpdateBrandStatPublishActivityCountSinceBrandOwnActivityPublished(ctx, q, activity.BrandID, asFeatureTypes)
		if err != nil {
			return err
		}
		slog.Infof("c 活动发布成功后更新品牌统计已发布活动数量 ok")

		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	s.activityService.ClearCacheOwn(activity.ID)
	res.ProcessStatus = toProcessStatus
	return
}

// PauseActivity 停用活动
func (s *ActivityAPIService) PauseActivity(ctx context.Context, req *activityGrpc.PauseActivityRequest) (res *activityGrpc.PauseActivityResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->PauseActivity:%v", req)
	res = &activityGrpc.PauseActivityResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activityID := req.Id
	activity, err := q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if activity.Owner == string(sqlc.EmActivityOwnerSpokesman) {
		if activity.PubUserID != req.GetUserId() {
			err = fmt.Errorf("用户%d无权停用此活动", req.GetUserId())
			return
		}
	} else if activity.Owner == string(sqlc.EmActivityOwnerBrand) {
		if activity.BrandID != req.GetBrandId() {
			err = fmt.Errorf("品牌%d与活动不匹配", req.GetBrandId())
			return
		}
	} else if activity.Owner == string(sqlc.EmActivityOwnerStore) {
		if activity.StoreID.Int64 != req.GetStoreId() {
			err = fmt.Errorf("门店%d与活动不匹配", req.GetStoreId())
			return
		}
	} else {
		err = fmt.Errorf("无效的活动owner")
		return
	}
	if activity.ProcessStatus != string(sqlc.EmActivityProcessStatusDraft) && activity.ProcessStatus != string(sqlc.EmActivityProcessStatusProcessing) {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     fmt.Sprintf("活动状态[%s]不允许暂停", activity.ProcessStatus),
		}
		return
	}
	toProcessStatus, err := s.activityService.PauseActivity(ctx, q, activityService.PauseResumeActivityParam{
		ActivityPtr: &activity,
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.ProcessStatus = toProcessStatus

	s.activityService.ClearCacheCascade(ctx, activity.ID)
	return
}

// ResumeActivity 启用活动
func (s *ActivityAPIService) ResumeActivity(ctx context.Context, req *activityGrpc.ResumeActivityRequest) (res *activityGrpc.ResumeActivityResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ResumeActivity:%v", req)
	res = &activityGrpc.ResumeActivityResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	activityID := req.Id
	activity, err := q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if activity.Owner == string(sqlc.EmActivityOwnerSpokesman) {
		if activity.PubUserID != req.GetUserId() {
			err = fmt.Errorf("用户%d无权启用此活动", req.GetUserId())
			return
		}
	} else if activity.Owner == string(sqlc.EmActivityOwnerBrand) {
		if activity.BrandID != req.GetBrandId() {
			err = fmt.Errorf("品牌%d与活动不匹配", req.GetBrandId())
			return
		}
	} else if activity.Owner == string(sqlc.EmActivityOwnerStore) {
		if activity.StoreID.Int64 != req.GetStoreId() {
			err = fmt.Errorf("门店%d与活动不匹配", req.GetStoreId())
			return
		}
	} else {
		err = fmt.Errorf("无效的活动owner")
		return
	}
	if activity.ProcessStatus != string(sqlc.EmActivityProcessStatusPaused) {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     fmt.Sprintf("活动状态[%s]不允许重新启用", activity.ProcessStatus),
		}
		return
	}

	toProcessStatus, err := s.activityService.ResumeActivity(ctx, q, activityService.PauseResumeActivityParam{
		ActivityPtr: &activity,
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.ProcessStatus = toProcessStatus

	s.activityService.ClearCacheCascade(ctx, activity.ID)
	return
}

/****************************************************************************************/
/*                            activity entity of query                                  */
/****************************************************************************************/

// GetActivityOfB 获取单个品牌活动
func (s *ActivityAPIService) GetActivityOfB(ctx context.Context, req *activityGrpc.GetActivityOfBRequest) (res *activityGrpc.GetActivityOfBResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->GetActivityOfB:%v", req)
	res = &activityGrpc.GetActivityOfBResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activity, err := q.GetActivity(ctx, req.Id)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	normalActivityWarehouses, err := q.ListNormalBrandActivityWarehousesByActivityID(ctx, activity.ID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	warehouseIDs := util.MapToInt64(util.ToGenericSlice(normalActivityWarehouses), func(v interface{}) int64 {
		val := v.(sqlc.ActivityWarehouse)
		return val.WarehouseID
	})

	normalActivityProductWithProductInfos, normalActivitySkus, err := s.activityService.FetchNormalProductAndSkus(ctx, q, activity.ID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	// slog.Infof("normalActivitySkus=>%d", len(normalActivitySkus))
	var activityConsignmentPtr *sqlc.ActivityConsignment
	var normalActivityConsignmentBonusSettings []sqlc.ActivityConsignmentBonusSetting
	if activityService.CheckCanEndorse(activity.Type) {
		activityConsignment, err2 := q.GetActivityConsignmentByActivityID(ctx, activity.ID)
		if err2 != nil {
			res.OpRet = &message.OperationResult{
				Success: false,
				Code:    400,
				Msg:     err2.Error(),
			}
			return
		}
		activityConsignmentPtr = &activityConsignment

		normalActivityConsignmentBonusSettings, err = q.ListNormalActivityConsignmentBonusSettingsByActivityID(ctx, activity.ID)
		if err != nil {
			res.OpRet = &message.OperationResult{
				Success: false,
				Code:    400,
				Msg:     err.Error(),
			}
			return
		}
	}

	res.ActivityOfB = transformActivityOfBEntityToPb(warehouseIDs, normalActivityProductWithProductInfos, normalActivitySkus, activityConsignmentPtr, normalActivityConsignmentBonusSettings)(activity)
	return
}

// GetActivityOfBAsFeature 获取品牌下作为功能的活动
func (s *ActivityAPIService) GetActivityOfBAsFeature(ctx context.Context, req *activityGrpc.GetActivityOfBAsFeatureRequest) (res *activityGrpc.GetActivityOfBResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->GetActivityOfBAsFeature:%v", req)
	res = &activityGrpc.GetActivityOfBResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activity, sqlErr := q.GetActivityAsBrandUniqueByBrandIDAndType(ctx, sqlc.GetActivityAsBrandUniqueByBrandIDAndTypeParams{
		BrandID: req.BrandId,
		Type:    req.Type,
	})
	if sqlErr != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    util.Int32IfThenElse(sql.ErrNoRows == sqlErr, 404, 400),
			Msg:     sqlErr.Error(),
		}
		return
	}

	normalActivityWarehouses, err := q.ListNormalBrandActivityWarehousesByActivityID(ctx, activity.ID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	warehouseIDs := util.MapToInt64(util.ToGenericSlice(normalActivityWarehouses), func(v interface{}) int64 {
		val := v.(sqlc.ActivityWarehouse)
		return val.WarehouseID
	})

	normalActivityProductWithProductInfos, normalActivitySkus, err := s.activityService.FetchNormalProductAndSkus(ctx, q, activity.ID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.ActivityOfB = transformActivityOfBEntityToPb(warehouseIDs, normalActivityProductWithProductInfos, normalActivitySkus, nil, nil)(activity)
	return
}

/****************************************************************************************/
/*                            activityJoins entity of helper                            */
/****************************************************************************************/


func transformListActivityItemOfBWithStatByBrandIDRowEntityToPb(o sqlc.ListActivityItemOfBWithStatsByBrandIDRow) *activityGrpc.ActivityItemOfBWithStatEntity {
	return &activityGrpc.ActivityItemOfBWithStatEntity{
		// activity
		Id:            o.ID,
		Modified:      sqlc.GoTimeToPBTimestamp(o.Modified),
		BrandId:       o.BrandID,
		PubUserId:     o.PubUserID,
		Name:          o.Name,
		Type:          o.Type,
		Intro:         string(o.Intro),
		ProcessStatus: o.ProcessStatus,
		Published:     sqlc.GoNTimeToPBTimestamp(o.Published),
		Begined:       sqlc.GoTimeToPBTimestamp(o.Begined),
		Ended:         sqlc.GoTimeToPBTimestamp(o.Ended),
		TimeRanges:    transformTimeRangeEntityToPb(o.TimeRanges),
		SaleMode:      o.SaleMode,

		// activity_stat
		OrderCount:     o.OrderCount,
		LatestAccessed: sqlc.GoTimeToPBTimestamp(o.LatestAccessed),
		Pv:             o.Pv,
		Uv:             o.Uv,
		Iv:             o.Iv,
	}
}

func mapActivityItemOfBWithStatByBrandIDEntityToPb(list []sqlc.ListActivityItemOfBWithStatsByBrandIDRow, f func(sqlc.ListActivityItemOfBWithStatsByBrandIDRow) *activityGrpc.ActivityItemOfBWithStatEntity) []*activityGrpc.ActivityItemOfBWithStatEntity {
	r := make([]*activityGrpc.ActivityItemOfBWithStatEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformListActivityItemOfSWithStatByUserIDAsSpokesmanRowEntityToPb(o sqlc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanRow) *activityGrpc.ActivityItemOfSWithStatEntity {
	return &activityGrpc.ActivityItemOfSWithStatEntity{
		// activity
		Id:            o.ID,
		Modified:      sqlc.GoTimeToPBTimestamp(o.Modified),
		BrandId:       o.BrandID,
		PubUserId:     o.PubUserID,
		Name:          o.Name,
		Type:          o.Type,
		Intro:         string(o.Intro),
		ProcessStatus: o.ProcessStatus,
		Published:     sqlc.GoNTimeToPBTimestamp(o.Published),
		Begined:       sqlc.GoTimeToPBTimestamp(o.Begined),
		Ended:         sqlc.GoTimeToPBTimestamp(o.Ended),
		TimeRanges:    transformTimeRangeEntityToPb(o.TimeRanges),
		SpokesmanId:   o.SpokesmanID.Int64,

		// activity_stat
		OrderCount:     o.OrderCount,
		LatestAccessed: sqlc.GoTimeToPBTimestamp(o.LatestAccessed),
		Pv:             o.Pv,
		Uv:             o.Uv,
		Iv:             o.Iv,
	}
}

func mapActivityItemOfSWithStatByUserIDAsSpokesmanEntityToPb(list []sqlc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanRow, f func(sqlc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanRow) *activityGrpc.ActivityItemOfSWithStatEntity) []*activityGrpc.ActivityItemOfSWithStatEntity {
	r := make([]*activityGrpc.ActivityItemOfSWithStatEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformListActivityItemOfU2BWithStatAndBrandInfosByUserIDRowEntityToPb(o sqlc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDRow) *activityGrpc.ActivityItemOfU2BWithStatAndBrandInfoEntity {
	return &activityGrpc.ActivityItemOfU2BWithStatAndBrandInfoEntity{
		// activity
		Id:                  o.ID,
		BrandId:             o.BrandID,
		PubUserId:           o.PubUserID,
		Name:                o.Name,
		Type:                o.Type,
		Intro:               string(o.Intro),
		ProcessStatus:       o.ProcessStatus,
		Published:           sqlc.GoNTimeToPBTimestamp(o.Published),
		Begined:             sqlc.GoTimeToPBTimestamp(o.Begined),
		Ended:               sqlc.GoTimeToPBTimestamp(o.Ended),
		TimeRanges:          transformTimeRangeEntityToPb(o.TimeRanges),
		SaleMode:            o.SaleMode,
		EndorseSpokesmanId:  o.EndorseSpokesmanID,
		EndorsedActivityIds: o.EndorsedActivityIds,

		// activity_stat
		OrderCount:     o.OrderCount,
		LatestAccessed: sqlc.GoTimeToPBTimestamp(o.LatestAccessed),
		Pv:             o.Pv,
		Uv:             o.Uv,
		Iv:             o.Iv,

		// brand info
		BrandName: o.BrandName,
		BrandPic:  o.BrandPic.String,
	}
}

func mapListActivityItemOfU2BWithStatAndBrandInfosByUserIDRowEntityToPb(list []sqlc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDRow, f func(sqlc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDRow) *activityGrpc.ActivityItemOfU2BWithStatAndBrandInfoEntity) []*activityGrpc.ActivityItemOfU2BWithStatAndBrandInfoEntity {
	r := make([]*activityGrpc.ActivityItemOfU2BWithStatAndBrandInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRowEntityToPb(o sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRow) *activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity {
	return &activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity{
		// activity
		Id:            o.ID,
		BrandId:       o.BrandID,
		PubUserId:     o.PubUserID,
		Name:          o.Name,
		Type:          o.Type,
		Intro:         string(o.Intro),
		ProcessStatus: o.ProcessStatus,
		Published:     sqlc.GoNTimeToPBTimestamp(o.Published),
		Begined:       sqlc.GoTimeToPBTimestamp(o.Begined),
		Ended:         sqlc.GoTimeToPBTimestamp(o.Ended),
		TimeRanges:    transformTimeRangeEntityToPb(o.TimeRanges),
		SpokesmanId:   o.SpokesmanID.Int64,
		Owner:         o.Owner,
		OwnerName:     o.OwnerName,
		OwnerPic:      o.OwnerPic,
		// activity_stat
		OrderCount:     o.OrderCount,
		LatestAccessed: sqlc.GoTimeToPBTimestamp(o.LatestAccessed),
		Pv:             o.Pv,
		Uv:             o.Uv,
		Iv:             o.Iv,
		// permission
		// CanManage:                    row.CanManage,
		// EndorseSpokesmanId:           row.EndorseSpokesmanID,
		// OpenEndorseToUser:            row.OpenEndorseToUser,
		// HasNotEndorsed:               row.HasNotEndorsed,
		// IsEndorsementEntranceDisplay: row.IsEndorsementEntranceDisplay,
	}
}

func mapListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRowEntityToPb(list []sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRow, f func(sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRow) *activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity) []*activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity {
	r := make([]*activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRowEntityToPb(o sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRow) *activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity {
	return &activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity{
		// activity
		Id:            o.ID,
		BrandId:       o.BrandID,
		PubUserId:     o.PubUserID,
		Name:          o.Name,
		Type:          o.Type,
		Intro:         string(o.Intro),
		ProcessStatus: o.ProcessStatus,
		Published:     sqlc.GoNTimeToPBTimestamp(o.Published),
		Begined:       sqlc.GoTimeToPBTimestamp(o.Begined),
		Ended:         sqlc.GoTimeToPBTimestamp(o.Ended),
		TimeRanges:    transformTimeRangeEntityToPb(o.TimeRanges),
		SpokesmanId:   o.SpokesmanID.Int64,
		Owner:         o.Owner,
		OwnerName:     o.OwnerName,
		OwnerPic:      o.OwnerPic,

		// activity_stat
		OrderCount:     o.OrderCount,
		LatestAccessed: sqlc.GoTimeToPBTimestamp(o.LatestAccessed),
		Pv:             o.Pv,
		Uv:             o.Uv,
		Iv:             o.Iv,

		// permission
		// CanManage:          row.CanManage,
		// EndorseSpokesmanId: row.EndorseSpokesmanID,
		// OpenEndorseToUser:  row.OpenEndorseToUser,
		// HasNotEndorsed:     row.HasNotEndorsed,
	}
}

func mapListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRowEntityToPb(list []sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRow, f func(sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRow) *activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity) []*activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity {
	r := make([]*activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRowEntityToPb(o sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRow) *activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity {
	return &activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity{
		// activity
		Id:            o.ID,
		BrandId:       o.BrandID,
		PubUserId:     o.PubUserID,
		Name:          o.Name,
		Type:          o.Type,
		Intro:         string(o.Intro),
		ProcessStatus: o.ProcessStatus,
		Published:     sqlc.GoNTimeToPBTimestamp(o.Published),
		Begined:       sqlc.GoTimeToPBTimestamp(o.Begined),
		Ended:         sqlc.GoTimeToPBTimestamp(o.Ended),
		TimeRanges:    transformTimeRangeEntityToPb(o.TimeRanges),
		SpokesmanId:   o.SpokesmanID.Int64,
		Owner:         o.Owner,
		OwnerName:     o.OwnerName,
		OwnerPic:      o.OwnerPic,

		// activity_stat
		OrderCount:     o.OrderCount,
		LatestAccessed: sqlc.GoTimeToPBTimestamp(o.LatestAccessed),
		Pv:             o.Pv,
		Uv:             o.Uv,
		Iv:             o.Iv,

		// permission
		// CanManage:          row.CanManage,
		// EndorseSpokesmanId: row.EndorseSpokesmanID,
		// OpenEndorseToUser:  row.OpenEndorseToUser,
		// HasNotEndorsed:     row.HasNotEndorsed,
	}
}

func mapListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRowEntityToPb(list []sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRow, f func(sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRow) *activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity) []*activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity {
	r := make([]*activityGrpc.ActivityItemOfU2CWithStatAndOwnerInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                            activityJoins entity of query                             */
/****************************************************************************************/

// ListActivityItemOfBWithStatsByBrandID 获取品牌活动Item+统计列表
func (s *ActivityAPIService) ListActivityItemOfBWithStatsByBrandID(ctx context.Context, req *activityGrpc.ListActivityItemOfBWithStatsByBrandIDRequest) (res *activityGrpc.ListActivityItemOfBWithStatsByBrandIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ListActivityItemOfBWithStatsByBrandID:%v", req)
	res = &activityGrpc.ListActivityItemOfBWithStatsByBrandIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	brandID := req.BrandId
	isAll := req.IsAll
	processStatuses := req.ProcessStatuses
	keyword := req.Keyword
	isKeywordEmpty := keyword == ""
	keywordLike := fmt.Sprintf("%%%s%%", keyword)
	asFeatureTypes := activityService.ActivitiesAsFeature

	total, err := q.CountActivityItemOfBWithStatsByBrandID(ctx, sqlc.CountActivityItemOfBWithStatsByBrandIDParams{
		AsFeatureTypes:  asFeatureTypes,
		Created:         ts,
		BrandID:         brandID,
		IsAll:           isAll,
		ProcessStatuses: processStatuses,
		IsKeywordEmpty:  isKeywordEmpty,
		Keyword:         keywordLike,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	rows, err := q.ListActivityItemOfBWithStatsByBrandID(ctx, sqlc.ListActivityItemOfBWithStatsByBrandIDParams{
		Limit:           req.Limit,
		Offset:          req.Offset,
		AsFeatureTypes:  asFeatureTypes,
		Created:         ts,
		BrandID:         brandID,
		IsAll:           isAll,
		ProcessStatuses: processStatuses,
		IsKeywordEmpty:  isKeywordEmpty,
		Keyword:         keywordLike,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.Total = total
	res.ActivityItemOfBWithStats = mapActivityItemOfBWithStatByBrandIDEntityToPb(rows, transformListActivityItemOfBWithStatByBrandIDRowEntityToPb)
	return
}

// ListActivityItemOfSWithStatsByUserIDAsSpokesman 获取代言活动Item+统计列表
func (s *ActivityAPIService) ListActivityItemOfSWithStatsByUserIDAsSpokesman(ctx context.Context, req *activityGrpc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanRequest) (res *activityGrpc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ListActivityItemOfSWithStatsByUserIDAsSpokesman:%v", req)
	res = &activityGrpc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	userID := req.UserId
	isAll := req.IsAll
	processStatuses := req.ProcessStatuses
	keyword := req.Keyword
	isKeywordEmpty := keyword == ""
	keywordLike := fmt.Sprintf("%%%s%%", keyword)
	asFeatureTypes := activityService.ActivitiesAsFeature

	total, err := q.CountActivityItemOfSWithStatsByUserIDAsSpokesman(ctx, sqlc.CountActivityItemOfSWithStatsByUserIDAsSpokesmanParams{
		AsFeatureTypes:  asFeatureTypes,
		Created:         ts,
		PubUserID:       userID,
		IsAll:           isAll,
		ProcessStatuses: processStatuses,
		IsKeywordEmpty:  isKeywordEmpty,
		Keyword:         keywordLike,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	rows, err := q.ListActivityItemOfSWithStatsByUserIDAsSpokesman(ctx, sqlc.ListActivityItemOfSWithStatsByUserIDAsSpokesmanParams{
		Limit:           req.Limit,
		Offset:          req.Offset,
		AsFeatureTypes:  asFeatureTypes,
		Created:         ts,
		PubUserID:       req.UserId,
		IsAll:           isAll,
		ProcessStatuses: processStatuses,
		IsKeywordEmpty:  isKeywordEmpty,
		Keyword:         keywordLike,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityItemOfSWithStats = mapActivityItemOfSWithStatByUserIDAsSpokesmanEntityToPb(rows, transformListActivityItemOfSWithStatByUserIDAsSpokesmanRowEntityToPb)
	return
}

// ListActivityItemOfU2BWithStatAndBrandInfosByUserID 获取代言的品牌活动Item+统计列表+品牌信息
func (s *ActivityAPIService) ListActivityItemOfU2BWithStatAndBrandInfosByUserID(ctx context.Context, req *activityGrpc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDRequest) (res *activityGrpc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ListActivityItemOfU2BWithStatAndBrandInfosByUserID:%v", req)
	res = &activityGrpc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	total, err := q.CountActivityItemOfU2BWithStatAndBrandInfosByUserID(ctx, sqlc.CountActivityItemOfU2BWithStatAndBrandInfosByUserIDParams{
		Created: ts,
		UserID:  req.UserId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}
	rows, err := q.ListActivityItemOfU2BWithStatAndBrandInfosByUserID(ctx, sqlc.ListActivityItemOfU2BWithStatAndBrandInfosByUserIDParams{
		Limit:   req.Limit,
		Offset:  req.Offset,
		Created: ts,
		UserID:  req.UserId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityItemOfU2BWithStatAndBrandInfos = mapListActivityItemOfU2BWithStatAndBrandInfosByUserIDRowEntityToPb(rows, transformListActivityItemOfU2BWithStatAndBrandInfosByUserIDRowEntityToPb)
	return
}

// ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesman C端用户获取活动列表及其统计、权限信息
func (s *ActivityAPIService) ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesman(ctx context.Context, req *activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRequest) (res *activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesman:%v", req)
	res = &activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	asFeatureTypes := activityService.ActivitiesAsFeature
	byUserID := req.ByUserId

	total, err := q.CountActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesman(ctx, sqlc.CountActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanParams{
		AsFeatureTypes: asFeatureTypes,
		Created:        ts,
		ByUserID:       byUserID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	arg := sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanParams{
		Limit:          req.Limit,
		Offset:         req.Offset,
		AsFeatureTypes: asFeatureTypes,
		Created:        ts,
		ByUserID:       byUserID,
	}
	rows, err := s.dao.Q.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesman(ctx, arg)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityItemOfU2CWithStatAndOwnerInfos = mapListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRowEntityToPb(rows, transformListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsSpokesmanRowEntityToPb)
	return
}

// ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollower C端用户获取关注对象(品牌、代言人)发布的活动列表及其统计、权限信息
func (s *ActivityAPIService) ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollower(ctx context.Context, req *activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRequest) (res *activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollower:%v", req)
	res = &activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	asFeatureTypes := activityService.ActivitiesAsFeature
	byUserID := req.ByUserId

	total, err := q.CountActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollower(ctx, sqlc.CountActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerParams{
		AsFeatureTypes: asFeatureTypes,
		Created:        ts,
		ByUserID:       byUserID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}
	rows, err := s.dao.Q.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollower(ctx, sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerParams{
		Limit:          req.Limit,
		Offset:         req.Offset,
		AsFeatureTypes: asFeatureTypes,
		Created:        ts,
		ByUserID:       byUserID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityItemOfU2CWithStatAndOwnerInfos = mapListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRowEntityToPb(rows, transformListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsFollowerRowEntityToPb)
	// 会有性能损耗,但是代码量精简了,暂时这个接口用,观察一下
	// res.ActivityItemOfU2CWithStatAndOwnerInfos = mapActivityItemOfU2CWithStatAndOwnerInfosForUserEntityEntityToPb(util.ToGenericSlice(rows), transformActivityItemOfU2CWithStatAndOwnerInfosForUserEntityToPb)
	return
}

// ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolver C端用户获取参与的活动列表及其统计、权限信息
func (s *ActivityAPIService) ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolver(ctx context.Context, req *activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRequest) (res *activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activityImp->ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolver:%v", req)
	res = &activityGrpc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	asFeatureTypes := activityService.ActivitiesAsFeature
	byUserID := req.UserId
	total, err := q.CountActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolver(ctx, sqlc.CountActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverParams{
		AsFeatureTypes: asFeatureTypes,
		Created:        ts,
		ByUserID:       byUserID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	rows, err := q.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolver(ctx, sqlc.ListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverParams{
		Limit:          req.Limit,
		Offset:         req.Offset,
		Created:        ts,
		AsFeatureTypes: asFeatureTypes,
		ByUserID:       byUserID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityItemOfU2CWithStatAndOwnerInfos = mapListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRowEntityToPb(rows, transformListActivityItemOfU2CWithStatAndOwnerInfosForUserByUserIDAsInvolverRowEntityToPb)

	return
}
